Chapter 3 THE INTEGER TYPE VARIABLE OUR FIRST INTEGER VARIABLE _________________________________________________________________ Examine the program named ONEINT.ADA for our ================ first example program with a variable. Some ONEINT.ADA programming languages do not require you to ================ predefine a variable before you use it. Instead, you simply begin using it and the system has some mechanism by which it creates the variable and makes it ready for your use. Ada requires you to specifically define every variable before you can use it. You must give the variable a name, which is any valid identifier, and you tell the compiler how you plan to use the variable by assigning a type to the variable. WHAT IS A TYPE? _________________________________________________________________ The type defines a set of values which the variable can have assigned to it, and it also defines a set of operations that can be performed on the variable. Ada is a strongly typed language since it has very strict rules limiting how a variable can be used. The compiler will not give you a usable program unless you follow all of the rules very carefully. A major part of the study of Ada involves the study of types and how to use typing as a programming aid. AN UNBROKEN RULE OF ADA, NEVER BROKEN _________________________________________________________________ Ada requires that anything you use must have been previously defined. This includes variables as well as constants, procedures, functions, and all other entities. At least one language, Pascal, makes this claim but breaks it in a few instances. Ada never breaks this rule. THE with STATEMENT _________________________________________________________________ When you include the with statement, as is done in line 2 of this program, it tells the system that there are a few functions, procedures, or packages that will be required by the system in order to run this program. The system opens up a window into the package named Text_IO which permits some checking to be done during compilation to see that you are using the functions and procedures Page 3-1 Chapter 3 - The Integer Type Variable correctly. Because it establishes the context, it is called a context clause. Much more will be said about this later. For now, it would be best if you simply include the line as shown. THE use STATEMENT _________________________________________________________________ Even though the functions and procedures from Text_IO are available for use, the system requires that we explicitly declare the package Text_IO with each use of one of its procedures unless we include the use clause. For now, we will simply say that including the use clause as we have done in line 3 will simplify the rest of the program. We will completely define this operation in a later lesson. THE package STATEMENT _________________________________________________________________ The statement in line 7 tells the system to instantiate a copy of the generic package named Integer_IO which is a part of the package Text_IO, use it to output INTEGER type variables, and call it Int_IO. That is quite a mouthful and far too advanced for us to attempt to understand at this point. Simply accept the fact that line 7 gives the system the ability to display INTEGER type variables, and line 8 makes it easier for us to use them. Once again, we will return to these statements in a later chapter and define them completely. WHAT IS AN INSTANTIATION? _________________________________________________________________ Since the word "instantiate" represents a new concept, we need a brief definition of what the word means. A generic package as defined in Ada is not actually a usable package, but only a template for a usable package. When we instantiate a copy of a generic package, we get a copy of the template with the undefined entities filled in and the resulting "instance" of the package is therefore usable in the program. Much more will be said about this later. Note that the word "instantiate" is not a reserved word, but only a word referring to an Ada operation. HOW DO WE DECLARE A VARIABLE? _________________________________________________________________ Back to the program named ONEINT.ADA. To understand the definition of a variable, examine the program at hand and specifically line 10. This declares a variable, which we will call Index, to be of Page 3-2 Chapter 3 - The Integer Type Variable type INTEGER, therefore defining an allowable range of values which can be assigned to it. Most microcomputers allow an INTEGER type variable to cover a range of -32768 to 32767 but the definition of Ada allows for flexibility here. We will see a way to determine exactly what the limits are for your compiler later in this chapter. The type also defines a number of operations which can be performed on the variable. More will be said of that later. The type INTEGER is used to declare a scalar variable, which is a variable that can contain a single value. The word INTEGER is not a reserved word but a predefined word which we can redefine if we so choose. We will not be doing that for a long time since it could cause untold problems in a program. You should know that it is possible for you to redefine this word, and many other similarly predefined words, to mean something entirely different from their predefined meanings. In the last chapter, we said that the declarative part of the program goes between the reserved words is and begin, and you will notice that we did indeed declare the variable named Index in that area of the program. The end result of line 10 is that we have a variable named Index which is of type INTEGER. As yet however, it does not contain a useful value. HOW DO WE USE THE VARIABLE IN A PROGRAM? _________________________________________________________________ In the last chapter we also said that the executable statements went between the begin and the end and you will see that we have some executable statements within that range, in lines 14 through 21 of this program. In line 14 we assign the value of 23 to the variable Index which is valid to do because 23 is within the range of allowable values that can be assigned to an INTEGER type variable. THE ASSIGNMENT OPERATOR _________________________________________________________________ The combination := can be read as "gets the value of". Line 14 can then be read as, "Index gets the value of 23." The equal sign alone is reserved for another use. Actually, if we say that Index = 23, it is only mathematically correct if Index is never changed, but since it is a variable and will be changed, the equality is not true. We have succeeded in assigning a value of 23 to the variable named Index and can use it in many different ways in an Ada program, but we will illustrate only very simple uses at this point. Page 3-3 Chapter 3 - The Integer Type Variable Line 15 instructs the system to output a line of text to the monitor and leave the cursor at the end of the line. In line 16, we use the predefined procedure named Put to tell the system to display the value of Index, which has the value of 23, on the monitor. The system will right justify the output in a default field width of 6 columns, because of its definition. This Put is part of the Int_IO package we declared earlier. The Put in line 15 is from Text_IO. Later in this tutorial you will understand which Put is from which package and why. Line 17 returns the cursor to the beginning of the next line. OUR FIRST ARITHMETIC _________________________________________________________________ Line 18 contains our first arithmetic statement and it will do exactly what it appears to do, "Index gets the value of Index with 12 added to it." The variable Index should now have a stored value of 23 + 12, or 35, which we verify by telling the system to display the new value of Index. The numeral 8 in line 20 tells the system to display the value right justified in a field 8 columns wide. We will discuss the Put procedure in detail later in this tutorial. If you remember that the statements are executed sequentially, you should have no difficulty following this program. Compile and execute this program being careful to observe that the two values of Index are displayed in fields of different widths. LET'S USE LOTS OF INTEGERS NOW _________________________________________________________________ Examine the program named MOREINTS.ADA and you ================ will see an example of using many variables of MOREINTS.ADA type INTEGER in a program. Lines 10 and 11 ================ illustrate that you can define one or more variables on a single line. All four variables are of type INTEGER and can be assigned values within the range of integer variables as defined for your particular compiler. Each of these variables have no value associated with them since they were created without an initial value. The executable part of the program can assign a value to each of them. The variable named Cat is also an INTEGER type variable but after being created, it is assigned an initial value of 12. Likewise Dog is created and initialized to a value of -5. It should not come as a surprise to you that the three variables in line 14 are created, and each is assigned an initial value of 1000. According to the Ada definition, line 14 is merely a shorthand for three different lines with a single variable declaration on each line as far as the Ada compiler is concerned. The same is true of line 11. This is a very subtle point, and has no consequence on Page 3-4 Chapter 3 - The Integer Type Variable the program at hand, but will make a difference later when we commence the study of arrays. NOW TO EXERCISE SOME OF THOSE VARIABLES _________________________________________________________________ Examining the executable part of the program we find the four arithmetic operations in lines 18 through 21 which should be self explanatory. Note that integer division in line 21 results in truncation, not rounding. The four values are displayed on the monitor in lines 22 through 25 in a format utilizing several statements per line which is simply a matter of style. Continuing with lines 27 and 28, we have examples of more complex mathematical calculations which should be clear to you. The order of precedence of mathematical operators is given in detail in section 4.5 of the LRM. The order of precedence is similar to other languages and follows common sense. A discussion of the order of precedence will be given at the end of the next chapter of this tutorial. If you feel you need more detail now, refer to the LRM. Lines 29 and 30 illustrate use of the mod and rem operators, each of which return the remainder which would be obtained following an integer divide operation. They differ only in the sign when negative numbers are involved and since negative numbers are rare when using these operators, little will be said except to give a brief statement of the differences. mod - gets the sign of the second operator. rem - gets the sign of the first operator. TWO MORE OPERATIONS _________________________________________________________________ After displaying the results, four more values are calculated, the first being the absolute value of the variable Dog in line 36. This is not a function, it is an operation defined with the reserved word abs. The fact that it is an operator will be very significant when we come to the portion of this tutorial that deals with overloading operators. The abs operator returns the absolute value of the variable given to it as a parameter. The operation in line 37 is an illustration of exponentiation of integer numbers. Since Cat has the value of 12, this line says that Index_2 gets the value of 12 raised to the 3rd power. The only rules for using exponentiation with integer values are, the exponent must be an integer type value, and it cannot be negative. Note that a zero value for an exponent is legal. Line 38 is a combination of several of the previous operations, and line 39 is an illustration of unary negation. Be sure to compile and execute this program and study the results. Page 3-5 Chapter 3 - The Integer Type Variable HOW DO WE DECLARE A CONSTANT? _________________________________________________________________ Examine INITEX.ADA for an example of a program ================ with some INTEGER type variables and some INITEX.ADA INTEGER type constants declared and used in it. ================ Lines 10 and 11 should be familiar to you now, but when we get to lines 13 through 16 we have a few new things to observe. DOZEN and GROSS are INTEGER type constants because of the reserved word constant in their declaration. The only difference between a constant and a variable is that a constant cannot be changed during execution of the program and in the present example, it would probably be silly to redefine how many elements are in a dozen. This is one of the things Ada can do to help you if you analyze your program right, because if you ever tried to change the value of DOZEN during program execution, Ada would give you an error message and you would eliminate one bug immediately. Notice that GROSS is defined in terms of DOZEN since the constant DOZEN is available when GROSS is initialized. Likewise, the constant TWO is defined in terms of BIG_NO in the next two lines. It should be obvious that a constant must have an initialization value assigned to it. TWO MORE DEFINITIONS _________________________________________________________________ Lines 15 and 16 contain underlines in the numeric values that the Ada compiler will simply ignore. You can put them in wherever you please to make the numeric literals more readable for you, but you cannot put more than one underline between each digit. The poor choice of underline locations in this example do not add to the ease of reading the numbers but illustrate the places where they can be located. The word INTEGER has been omitted from lines 15 and 16, which makes the type of these constants slightly different from the other two but we will have to learn a bit more before we can understand or appreciate the value of doing this. Lines 20 through 28, in the executable part of the program, should be easy for you to understand on your own, so they will be left to your study. DECLARING LITERAL CONSTANTS _________________________________________________________________ Lines 30 through 32 give examples of declaration of literal values for constants using the exponential notation. The exponent can be indicated with either case of "E" and the number following it must Page 3-6 Chapter 3 - The Integer Type Variable be positive for an integer literal. Lines 33 through 36 give examples of the use of a base other than 10. The radix of the number is given prior to the first "#" sign, and can be any value from 2 through 16, the radix itself being given in decimal notation. The value is given between "#" signs and can be followed by an optional exponent, the exponent being given in the defined base. If no radix is given, base 10 is assumed as in lines 30 through 32 of this example program. The executable part of this program should be very clear to you so you can study it on your own before you compile and execute it. TYPES AND SUBTYPES _________________________________________________________________ Examine the program SUBTYPES.ADA for your first ================ look at a user defined type. We mentioned SUBTYPES.ADA earlier that the range of a variable of type ================ INTEGER could be different on different computers or with different compilers on the same computer. Ada gives us the ability to define our own type in such a way that it will be identical on every computer and with every Ada compiler. A DIFFERENT TYPE IS INCOMPATIBLE _________________________________________________________________ Line 10 defines a new integer type which will cover the range of -10,000 to 20,000 because of the use of the reserved word range to limit the available range of values that can be assigned to a variable of this type. Notice carefully that we called this an integer type, not a type INTEGER. Since it is an integer type, it has all of the properties defined earlier in this chapter but a variable of this type can only be assigned a value from -10,000 to 20,000. The actual range is given by specifying the lower and upper limits separated by two decimal points. The limits can be of arbitrary complexity as illustrated in lines 23 and 24. In addition, we have actually defined an entirely new type, and since Ada does very strong type checking, it will not allow you to assign a value directly from a variable of type INTEGER to a variable of our new type, or vice versa. The variable My_Int is defined with the new type in line 11. We will return to consideration of this variable later. The package declaration in line 13 is similar to the package declaration in line 7 except that it is used to tell the system how to output variables of type MY_INT_TYPE to the monitor. We will discuss this in detail later. Page 3-7 Chapter 3 - The Integer Type Variable A NEW SUBTYPE IS COMPATIBLE WITH ITS PARENT _________________________________________________________________ In line 16, we define a new subtype which is of the parent type INTEGER except that it covers a limited range, then we declare a variable named Thing of the new subtype in line 17. Any attempt to assign a value to the variable Thing which is outside of its assigned range, will result in an error. If you were running a small company with 23 employees and you assigned them each a unique number from 1 to 23, you would be interested if the payroll program tried to generate a paycheck for employee numbered 36, for example, because there would definitely be something wrong. A limited subrange could save you a lot of money in a case such as that. ASSIGNMENT MUST BE TYPE COMPATIBLE _________________________________________________________________ Anytime a value is assigned to a variable, the type assigned to it must be of its declared type or a compiler error will be generated. This will always be true in Ada and is one of the most important concepts behind its design. This is to prevent us from making the silly little mistakes which we humans are so good at making. The variable Count is defined as an INTEGER type variable and Stuff is defined as a limited range INTEGER also. Remember that Thing is declared to be a subtype of INTEGER, so it is also a limited range INTEGER type variable. Because of the way these three variables are defined, they can be freely assigned to each other as long as the values assigned are within their respective ranges. This is because they are all of their parent type of INTEGER, and various assignments among them are illustrated in lines 28 through 30. If we tried to assign the value of Thing to My_Int, the computer would give a compile error because they are of different types, but an explicit type conversion can be used to do the assignment as illustrated in line 33. By including the variable to convert to a new type in parentheses and preceding the parentheses with the desired type name, the system will convert the type as illustrated. The addition to Thing is completed and the entire expression inside of the parentheses is changed in type, by the explicit type conversion, to the desired type of the left side of the assignment statement. In line 34, the type is changed to the new type before the value of 17 is added to it, which should lead you to ask a question about the type of the constant 17. HOW CAN 17 BE ADDED TO EITHER TYPE? _________________________________________________________________ The constant 17 is of a very special type defined by Ada as type "universal_integer" which can be combined with any of the integer Page 3-8 Chapter 3 - The Integer Type Variable types without specific conversion. This term will be used in many ways in future lessons. The type universal_integer is compatible with all integer types and has a range with no limits. The range is effectively minus infinity to plus infinity. The type universal_integer is used for all literal values, but it is not available for your use in declaring a variable. NOW FOR A SUBRANGE ERROR _________________________________________________________________ Lines 33 and 34 were essentially the same because they resulted in the same answer, and lines 36 and 37 would appear to be the same, but they are not. In line 36, the value of Thing, which is 18, is converted to type MY_INT_TYPE and 10 is subtracted from it. Both 18 and 8 are within the specified range of MY_INT_TYPE so there is no error. In line 37 however, the result of the subtraction has the type of Thing and even the intermediate result is required to be within the range of 12 to 144. The result of 8 is outside of the required range so a run-time error is signalled in a special way called raising an exception. We will discuss the exception shortly but first notice that if we could get past the error, we could change the type of the result to MY_INT_TYPE and everything would work as desired. INTERMEDIATE RESULTS OF CALCULATIONS _________________________________________________________________ The LRM allows the limits of intermediate results to be checked against the limits of the parent type rather than the limits of the subtype. Line 37 therefore, may not give an error indicating that the intermediate result is out of the allowable range. This will depend on your compiler. WHAT IS AN EXCEPTION? _________________________________________________________________ We will have a lot to say about exceptions as we progress through this tutorial but a very brief description is needed at this time. When an Ada program is running, and a potentially disastrous error is detected, it would be good for you, the programmer, to be able to tell the system what to do with the error rather than cause a complete termination of the program. Ada gives you that capability through the use of exception handlers that you write and include in your program. In the above case, when the program detected the value of 8 as being out of the allowable range of that type of variable, it would signal your program that the error occurred, and if you did nothing, the Ada system would terminate the program. The proper Ada terminology for signalling you is called "raising an exception", and in the case of an out-of-bounds value, the exception named Constraint_Error would be raised. You could then trap this error and handle it any way you choose to. Page 3-9 Chapter 3 - The Integer Type Variable There are several different exceptions that the system can raise and you can define your own exceptions that your program can raise and respond to. We will have a lot more to say about exceptions later in this tutorial. A little study on your part should reveal why line 41 also has a run time error that will raise the exception Constraint_Error, if execution continues to that statement. ANOTHER LOOK AT THE universal_integer _________________________________________________________________ Before we leave this program we must look at lines 21 and 22 where we first define START and STOP as constants with no type indication. These constants are therefore of type "universal_integer" and can be used in the range definitions of the next two lines even though the two lines are of different parent types. If we had included the word INTEGER in the definitions in lines 21 and 22, they could not be used to define the limits of Example2 because it is of a different parent type. The example program named INITEX.ADA had examples of INTEGER constants (DOZEN and GROSS) and universal_integer type constants (BIG_NO and TWO). The type universal_integer is actually a hidden type that is type compatible with all integer types. It should also be observed that the limits of the range in these definitions are based on previously defined entities and can be of arbitrary complexity as long as they evaluate to the right types. The limits must also be within the range of the parent type or a compile error will result. HOW TO DEFINE TYPES AND SUBTYPES _________________________________________________________________ To declare types or subtypes, here are two simple formulas which can be followed. type is ; subtype is ; Note that each declaration starts with a reserved word and includes the reserved word is between the name and the definition. It should be pointed out that Ada permits new types, subtypes, and variable declarations to be done in any order as long as everything is defined before it is used. Compile and execute SUBTYPES.ADA and observe the exception error as reported by your runtime system. The exception may be raised at line 37, depending on your compiler, where the value of 8 is outside of the allowable range of 12 through 144. The error message will vary with different compilers. Page 3-10 Chapter 3 - The Integer Type Variable Much more will be said about types and subtypes in chapter 7 of this tutorial. WHAT ARE ATTRIBUTES? _________________________________________________________________ Ada has a rather large list of attributes ================ available for you as a programming aid. For an INTATTRS.ADA example of a program that contains, and ================ therefore illustrates the use of attributes, examine the program named INTATTRS.ADA. A new type is defined in line 10 with a limited range to illustrate that attributes are available even for user defined types. Two additional integer types are introduced in lines 13 and 14, the NATURAL and POSITIVE types. The POSITIVE type includes all integers greater than or equal to 1, and the NATURAL type includes all integers greater than or equal to 0. Both of these are available with your Ada compiler, and both are subtypes of INTEGER, so all variables of these three types can be freely mixed with no type errors. Attributes are used to gain access to various limits within the program. For example it may be necessary to know the upper limit of a variable of some type because it is of some strange subtype. An attribute can be used to find this limit, specifically the attribute LAST as illustrated in line 31 of this program. By combining the type name and the attribute in question with a "tick" or apostrophe, the upper limit of the range of the type is returned. The attribute FIRST is used to find the lowest value allowed by the subrange. The attribute SIZE gives the storage size of the type in bits of memory. Other attributes are available for integer types. A complete list of available attributes is given in Appendix A of the LRM. You should spend a few minutes reviewing the list at this time even though you will understand little of what is presented there. In the near future, you will understand most of the material included there. TYPE CONVERSIONS _________________________________________________________________ Note the type conversions in lines 66, 70, 72, and 75. The values could be output directly with the BUG_RANGE type by instantiating another new copy of Text_IO.Integer_IO in a manner similar to that done in the example program named SUBTYPES.ADA. Compile and run this program and you will get a listing of the number of bits required by your compiler to store each of the four types along with the range covered by each of the four types. Page 3-11 Chapter 3 - The Integer Type Variable PROGRAMMING EXERCISES _________________________________________________________________ 1. Write a program with some types containing some constrained limits and see what errors occur when you exceed their limits. 2. Try to assign some wrong type of data to some variables and try to mix up some types in arithmetic statements. Study the compiler error messages. 3. Modify INTATTRS.ADA to output the BUG_RANGE attributes directly by instantiating a new copy of the generic package Text_IO.Integer_IO. Don't spend too much time on this exercise before you look at the answer. It contains a new construct, at least new to you. Page 3-12